# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

#
# Original Author: Serge V. Zarviroff <zarviroff@gmail.com>
# Purpose: make it easy to create and emerge ebuilds for packages' additives (such as mods, scripts, etc.;
# primarily designed for x3 - Reunion, but should work with any target app as it is very universal).
#
# Bugs, patches to zarviroff@gmail.com
#

# Description and usage:
#
# Sometimes you wish that some package should be tricked in some special way depending on the order it was installed in.
#
# Design note:
# It's faster and more efficient to do its job the way it does. It's not a big deal to rewrite it so it would make a sorted 
# array of pkg's (tested already) or do the sort live comparing the contents of the trackdir and dbpkg. Those methods seem
# right and beautiful, but with the growth of tracked packages the amount of work your pc would have to make grows just
# insanely. And when reinstall is happening that amount twices. It's like the act of rape of your hdd, cpu and ram.
# It's not the lame excuse of mine for not choosing the hard "right" path. I actually rewrote if from the sorted-array-of-pkgs
# design to what it is now.
# So it should be the way it is now. It's fast, it's awesome, it's sexy.
#
# Usage:
# 	inherit tracker
# Then, during any phase prior to src_install call this:
# 	tracker_mktrackfile $trackdir $trackfile_dest $category $pn $pvr $strictorder
#		Example:
#		tracker_mktrackfile "/opt/x3/x3-collisions" "${clns_SOURCESROOT}/x3-collisions" "games-simulation" "x3-somemod" "9999" "1"
#	Note: it doesn't modify the trackdir (live filesystem). In case of reinstall it just needs to get the very first time
#		the package has been installed, not that resides in BUILD_TIME dbpkg's file.
# where
#	trackdir - path to a directory on your live filesystem, where trackfiles reside
#	trackfile_dest - path to a directory in the WORKDIR, where a trackfile will be created
#	strictorder - 1 or 0 - should the order of a package being installed be dependent on other strickordered pkg's or not
#		Example:
#			You install a package A with strictorder=1
#			Then a package B with strictorder=0
#			Then a package C with strictorder=1
#			Then a package D with strictorder=1
#			After that, if you try to unmerge A, this eclass will halt the unmerge and print a warn that you can't
#			do that until you unmerge first D then C. And only after and in the specified order you could unmerge A.
#			Package B, off course, could be unmerged anytime as its order is not strict.
#
# Note that the last parameter is not strict itself. You can omit it while calling tracker_mktrackfile. If you do this
# the package strictorder will be defaulted to 0.


pDB="/var/db/pkg"
mkLocalTHeaders="local tCAT tPN tPVR tSO tBT"
tFileBasicMask="tBT=*:tCAT=*:tPN=*:tPVR=*"

tracker_markreinstall() {
	tracker_REINSTALL="/tmp/${PN}.reinstall"
	local installedatom="$(ls ${pDB}/${CATEGORY} 2>/dev/null | grep ^${PN})"
	if [[ -n "${installedatom}" ]] && [[ -e "${pDB}/${CATEGORY}/${installedatom}/CONTENTS" ]]
	then
		touch "${tracker_REINSTALL}"
	fi
}

tracker_isReinstall() {
	if [[ -e "${tracker_REINSTALL}" ]]
	then
		return 0
	else
		return 42
	fi
}

# Usage: tracker_isLastStrict $trackdir ${category} ${PN}
# Returns normal exit status (0) if ${PN} is the last strickordered atom installed or if there
# are no strickordered packages at all in the track.
tracker_isLastStrict() {
	local IFS=$'\n'
	if tracker_exists "${1}"
	then
		# returns non-zero status, if it's not last
		return $(ls ${1}/${tFileBasicMask}:tSO=1 2>/dev/null | tail -n1 | grep -q ^.*tCAT=${2}:tPN=${3})
	else
		# returns ok status if there are no tracks at all
		return 0
	fi
	return 0
}

# Usage tracker_LastStrictAtom $trackdir
tracker_LastStrictAtom() {
	local IFS=$'\n'
	if tracker_exists "${1}"
	then
		eval ${mkLocalTHeaders}
		local trackfile
		for trackfile in $(tracker_trackfiles "${1}" "*")
		do
			tracker_parseTrackFile "${trackfile}"
			if (( "${tSO}" ))
			then
				echo "${tCAT}/${tPN}-${tPVR}"
				return 0
			fi
		done
	else
		echo "" && return 0
	fi
	echo "" && return 0
}

# Usage: tracker_isLast $trackdir $CATEGORY $PN
# Returns normal exit status if the last installed atom is ${PN} or if there were no packages installed at all.
tracker_isLast() {
	local IFS=$'\n'
	if tracker_exists "${1}"
	then
		# returns non-zero status, if it's not last
		return $(ls ${1}/${tFileBasicMask} 2>/dev/null | tail -n1 | grep -q ^.*tCAT=${2}:tPN=${3})
	else
		# returns ok status if there are no tracks at all
		return 0
	fi
	return 0
}

# Usage: tracker_trackfiles $trackdir $so=(1|0|*)
tracker_trackfiles() {
	local trackfile
	for trackfile in $(ls -r ${1}/${tFileBasicMask}:tSO=${2} 2>/dev/null | sed 's|^.*/||g')
	do
		echo ${trackfile}
	done
}

# Usage tracker_printErrorsUntil $trackdir $category $pn $so=(1|0|*)
tracker_printErrorsUntil() {
	local IFS=$'\n'
	if tracker_exists "${1}"
	then
		eval ${mkLocalTHeaders}
		local trackfile
		for trackfile in $(tracker_trackfiles "${1}" "${4}")
		do
			tracker_parseTrackFile "${trackfile}"
			if [[ "${tCAT}/${tPN}" == "${2}/${3}" ]]
			then
				return 0
			fi
			eerror "=${tCAT}/${tPN}-${tPVR}"
		done
	else
		return 0
	fi
	return 0
}

tracker_print() {
	if tracker_exists "${1}"
	then
		einfo "This is a summary of packages you have installed in a descending order:"
		einfo ""
		eval ${mkLocalTHeaders}
		local trackfile
		for trackfile in $(tracker_trackfiles "${1}" "*")
		do
			tracker_parseTrackFile "${trackfile}"
			einfo "=${tCAT}/${tPN}-${tPVR} (STRICTORDER=${tSO}) built at $(date -d @${tBT})"
		done
		einfo ""
	fi
}

# Usage: tracker_findOwner $trackdir $filename (anychar)
# Returns zero-length string if the filename isn't owned by one of the tracked packages.
# Rerurns CATEGORY/PN otherwise.
# or CATEGORY/PF if the caller provided the third argument
tracker_findOwner() {
	local IFS=$'\n'
	if tracker_exists "${1}"
	then
		eval ${mkLocalTHeaders}
		local trackfile
		for trackfile in $(tracker_trackfiles "${1}" "*")
		do
			tracker_parseTrackFile "${trackfile}"
			if grep -q "${2}" "${pDB}/${tCAT}/${tPN}-${tPVR}/CONTENTS"
			then
				if [[ -n "${3}" ]]
				then
					echo "${tCAT}/${tPN}-${tPVR}"
				else
					echo "${tCAT}/${tPN}"
				fi
				return 0
			fi
		done
	else
		return 0
	fi
	echo "" && return 42
}

# Usage tracker_getAtomIfInstalled $trackpath $category $pn
# returns ${tCAT}/${tPN}-${tPVR}
tracker_getAtomIfInstalled() {
	local IFS=$'\n'
	if tracker_exists "${1}"
	then
		local trackfile=$(find ${1} -type f -name "tBT=*:tCAT=${2}:tPN=${3}:*" -printf "%f\n")
		eval ${mkLocalTHeaders}
		if tracker_parseTrackFile "${trackfile}"
		then
			echo "${tCAT}/${tPN}-${tPVR}"
		else 
			echo "" && return 0
		fi
	else
		echo "" && return 0
	fi
	echo "" && return 0
}

# Usage tracker_exists $trackpath
tracker_exists() {
	local IFS=$'\n'
	if [[ -e "${1}" ]]
	then
		return $(ls ${1} | grep -q tBT=.*$ 2>/dev/null)
	fi
	return 42
}

# Usage: tracker_getBuildTime $trackdir $category $pn
tracker_getBuildTime() {
	if tracker_exists "${1}"
	then
		echo $(find ${1} -type f -name "tBT=*:tCAT=${2}:tPN=${3}:*" -printf "%f\n" | sed 's/:tCAT=.*$//;s/^.*tBT=//')
		return 0
	else
		echo "" && return 0
	fi
	return 42
}

# Usage: tracker_mktrackfile $trackdir $trackfile_dest $category $pn $pvr $strictorder
#								1		2				3		 4	 5 	  6
tracker_mktrackfile() {
	local track_BUILD_TIME=$(tracker_getBuildTime ${1} ${3} ${4})
	if [[ -z "${track_BUILD_TIME}" ]]
	then
		track_BUILD_TIME=$(date +%s)
	fi
	local tSO="${6}"
	if [[ -z "${6}" ]]
	then
		tSO=0
	fi
	touch "${2}/tBT=${track_BUILD_TIME}:tCAT=${3}:tPN=${4}:tPVR=${5}:tSO=${tSO}"
}

tracker_clean() {
	rm "${tracker_REINSTALL}" -f
}

# declare local vars tCAT tPN tPVR tSO tBT prior calling it.
# you can use eval ${mkLocalTHeaders} - it'll declare them as local.
# Usage: tracker_parseTrackFile trackfile_string
tracker_parseTrackFile() {
	if [[ -n "${1}" ]]
	then
		local token
		local IFS=':'
		for token in "${1}"
		do
			eval ${token}
		done
		return 0
	else
		return 42
	fi
}